Passed
Push — develop ( d433db...110c59 )
by Andrew
04:14
created

webpack.prod.js ➔ extract   A

Complexity

Conditions 1
Paths 2

Size

Total Lines 3
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 2
dl 0
loc 3
rs 10
c 0
b 0
f 0
cc 1
nc 2
nop 1
1
// webpack.prod.js - production builds
2
const LEGACY_CONFIG = 'legacy';
3
const MODERN_CONFIG = 'modern';
4
5
// node modules
6
const webpack = require('webpack');
7
const glob = require("glob-all");
8
const path = require('path');
9
const git = require('git-rev-sync');
10
const moment = require('moment');
11
12
// webpack plugins
13
const merge = require('webpack-merge');
14
const CleanWebpackPlugin = require('clean-webpack-plugin');
15
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
16
const TerserPlugin = require('terser-webpack-plugin');
17
const OptimizeCSSAssetsPlugin = require("optimize-css-assets-webpack-plugin");
18
const PurgecssPlugin = require("purgecss-webpack-plugin");
19
const whitelister = require('purgecss-whitelister');
20
21
// config files
22
const pkg = require('./package.json');
23
const common = require('./webpack.common.js');
24
25
// Custom PurgeCSS extractor for Tailwind that allows special characters in
26
// class names.
27
//
28
// https://github.com/FullHuman/purgecss#extractor
29
class TailwindExtractor {
30
    static extract(content) {
31
        return content.match(/[A-Za-z0-9-_:\/]+/g) || [];
32
    }
33
}
34
35
// File banner banner
36
const configureBanner = () => {
37
    return {
38
        banner: [
39
            '/*!',
40
            ' * @project        ' + pkg.copyright,
41
            ' * @name           ' + '[filebase]',
42
            ' * @author         ' + pkg.author,
43
            ' * @build          ' + moment().format('llll') + ' ET',
44
            ' * @release        ' + git.long() + ' [' + git.branch() + ']',
45
            ' * @copyright      Copyright (c) ' + moment().format('YYYY') + ' ' + pkg.copyright,
46
            ' *',
47
            ' */',
48
            ''
49
        ].join('\n'),
50
        raw: true
51
    };
52
};
53
54
// Configure PurgeCSS
55
const configurePurgeCss = () => {
56
    let paths = [];
57
    // Configure whitelist paths
58
    for (const [key, value] of Object.entries(pkg.purgeCss.paths)) {
59
        paths.push(path.join(__dirname, value));
60
    }
61
62
    return {
63
        paths: glob.sync(paths),
64
        whitelist: whitelister(pkg.purgeCss.whitelist),
65
        whitelistPatterns: pkg.purgeCss.whitelistPatterns,
66
        extractors: [{
67
            extractor: TailwindExtractor,
68
            extensions: pkg.purgeCss.extensions
69
        }]
70
    };
71
};
72
73
// Configure clean webpack
74
const configureCleanWebpack = () => {
75
    return {
76
        root: path.resolve(__dirname, pkg.paths.dist.base),
77
        verbose: true,
78
        dry: false
79
    };
80
};
81
82
// Configure terser
83
const configureTerser = () => {
84
    return {
85
        cache: true,
86
        parallel: true,
87
        sourceMap: true
88
    };
89
};
90
91
92
// Postcss loader
93
const configurePostcssLoader = (buildType) => {
94
    if (buildType === LEGACY_CONFIG) {
95
        return {
96
            test: /\.(pcss|css)$/,
97
            use: [
98
                MiniCssExtractPlugin.loader,
99
                {
100
                    loader: 'css-loader',
101
                    options: {
102
                        importLoaders: 2,
103
                        sourceMap: true
104
                    }
105
                },
106
                {
107
                    loader: 'resolve-url-loader'
108
                },
109
                {
110
                    loader: 'postcss-loader',
111
                    options: {
112
                        sourceMap: true
113
                    }
114
                }
115
            ]
116
        };
117
    }
118
    if (buildType === MODERN_CONFIG) {
119
        return {
120
            test: /\.(pcss|css)$/,
121
            loader: 'ignore-loader'
122
        };
123
    }
124
};
125
126
// Configure optimization
127
const configureOptimization = (buildType) => {
128
    if (buildType === LEGACY_CONFIG) {
129
        return {
130
            splitChunks: {
131
                cacheGroups: {
132
                    default: false,
133
                    common: false,
134
                    styles: {
135
                        name: pkg.vars.cssName,
136
                        test: /\.(pcss|css|vue)$/,
137
                        chunks: 'all',
138
                        enforce: true
139
                    }
140
                }
141
            },
142
            minimizer: [
143
                new TerserPlugin(
144
                    configureTerser()
145
                ),
146
                new OptimizeCSSAssetsPlugin({
147
                    cssProcessorOptions: {
148
                        map: {
149
                            inline: false,
150
                            annotation: true,
151
                        },
152
                        safe: true,
153
                        discardComments: true
154
                    },
155
                })
156
            ]
157
        };
158
    }
159
    if (buildType === MODERN_CONFIG) {
160
        return {
161
            minimizer: [
162
                new TerserPlugin(
163
                    configureTerser()
164
                ),
165
            ]
166
        };
167
    }
168
};
169
170
// Production module exports
171
module.exports = [
172
    merge(
173
        common.legacyConfig,
174
        {
175
            output: {
176
                filename: path.join('./js', '[name]-legacy.[chunkhash].js'),
177
            },
178
            mode: 'production',
179
            devtool: 'source-map',
180
            optimization: configureOptimization(LEGACY_CONFIG),
181
            module: {
182
                rules: [
183
                    configurePostcssLoader(LEGACY_CONFIG),
184
                ],
185
            },
186
            plugins: [
187
                new CleanWebpackPlugin(pkg.paths.dist.clean,
188
                    configureCleanWebpack()
189
                ),
190
                new MiniCssExtractPlugin({
191
                    path: path.resolve(__dirname, pkg.paths.dist.base),
192
                    filename: path.join('./css', '[name].[chunkhash].css'),
193
                }),
194
                new PurgecssPlugin(
195
                    configurePurgeCss()
196
                ),
197
                new webpack.BannerPlugin(
198
                    configureBanner()
199
                ),
200
            ]
201
        }
202
    ),
203
    merge(
204
        common.modernConfig,
205
        {
206
            output: {
207
                filename: path.join('./js', '[name].[chunkhash].js'),
208
            },
209
            mode: 'production',
210
            devtool: 'source-map',
211
            optimization: configureOptimization(MODERN_CONFIG),
212
            module: {
213
                rules: [
214
                    configurePostcssLoader(MODERN_CONFIG),
215
                ],
216
            },
217
            plugins: [
218
                new webpack.BannerPlugin(
219
                    configureBanner()
220
                ),
221
            ]
222
        }
223
    ),
224
];
225